/*********************************************************************************
 *     Copyright:  (C) 2022 Nikel
 *                 All rights reserved.
 *
 *    Filename:  at_cmd.c
 *    Description:  This file is for AT command module
 *
 *    Version:  1.0.0
 *    Author:  zhouyanlin <www.zhouyanlin1222@qq.com>
 *    ChangeLog:  1, Release initial version on "06/04/22 22:51:05"
 *
 ********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "at_cmd.h"

#define	ATCMD_REPLY_LEN		256		/* AT command reply length */

/*
 * Description: AT command debug macros ,
 * 				comment the following two macro definitions
 * 				to disable debug printing
 *
 * */

//#define CONFIG_AT_CMD_DEBUG
//#define CONFIG_AT_CMD_PRINT

#ifdef CONFIG_AT_CMD_DEBUG
#define at_dbg(format,args...) printf(format, ##args)
#else
#define at_dbg(format,args...) do{} while(0)
#endif

#ifdef CONFIG_AT_CMD_PRINT
#define at_printf(format,args...) printf(format, ##args)
#else
#define at_printf(format,args...) do{} while(0)
#endif

/* Send AT command */
int send_atcmd(char *atcmd, char *expect_reply, unsigned int timeout, char *outbuf, int size_outbuf)
{
	int                       rv = -3;
	unsigned int              i;
	char                     *expect;

	/* check function input arguments validation */
	if(  NULL == atcmd || strlen(atcmd)<=0 )
	{
		at_printf("%s-->ERROR: Invalid input arguments\r\n", __FUNCTION__);
		return -1;
	}

	at_dbg("\r\nStart send AT command: %s", atcmd);
	clear_atcmd_rxbuf();
	HAL_UART_Transmit(at_uart, (uint8_t *)atcmd, strlen(atcmd), 1000);

	expect = expect_reply ? expect_reply : "OK\r\n";

	/* Receive AT reply string by UART interrupt handler, stop by "OK/ERROR" or timeout */
	for(i=0; i<timeout; i++)
	{
		if( strstr(g_atcmd_rxbuf, expect) )
		{
			at_printf("AT command Got expect reply '%s'\r\n", expect);
			rv = 0;
			goto CleanUp;
		}

		if( strstr(g_atcmd_rxbuf, "ERROR\r\n") || strstr(g_atcmd_rxbuf, "FAIL\r\n"))
		{
			rv = -2;
			goto CleanUp;
		}

		HAL_Delay(1);
	}


CleanUp:
	if( outbuf && size_outbuf>0 )
	{
		strncpy(outbuf, g_atcmd_rxbuf, size_outbuf);
	}
	at_dbg("<<<< AT command reply:\r\n%s", g_atcmd_rxbuf);
	return rv;
}

/* Send atcmd and check OK
 *
 *  Description: Send AT command which will only reply by "OK" or "ERROR", such as AT:
 *                 Reply:   \r\nOK\r\n
 * Return Value: 0: OK     -X: Failure
 */
int send_atcmd_check_ok(char *atcmd, unsigned int timeout)
{
    if( NULL == atcmd )
    {
    	at_printf("%s--->Invalid input arguments\r\n",__FUNCTION__);
        return -1;
    }

    return send_atcmd(atcmd, NULL, timeout, NULL, 0);
}


/*
 *  Description: Send AT command which will reply by a value directly in a single line, such as AT+CGMM:(生产厂商的标识)
 *                  Reply:   \r\nEC20F\r\nOK\r\n
 *
 * Return Value: 0: OK     -X: Failure
 */
int send_atcmd_check_value(char *atcmd, unsigned int timeout, char *outbuf, int size_outbuf)
{
    int                     i = 0;
    int                     rv;
    char                    buf[ATCMD_REPLY_LEN];
    char                   *ptr_start, *ptr_end;

    if( !atcmd || !outbuf || size_outbuf<=0 )
    {
    	at_printf("%s--->Invalid input arguments\r\n", __FUNCTION__);
        return -1;
    }

    /*send AT command*/
    rv = send_atcmd(atcmd, NULL, timeout, buf, sizeof(buf));
    if( rv < 0 )
    {
        return -2;
    }

    /*Find start position */
    ptr_start=strchr(buf, '\n'); /* found '\n' before the value */
    if( !ptr_start )
    {
        return -3;
    }
    ptr_start++;   /* skip '\n' */

    /*Find end position */
    ptr_end=strstr(buf, "\r\n\r\nOK\r\n");
    if( !ptr_end )
    {
        return -3;
    }

    /*copy reply out */
    memset(outbuf, 0, size_outbuf);
    while(ptr_start<ptr_end && i<size_outbuf)
    {
    	outbuf[i++] = *ptr_start;
        ptr_start ++;
    }

    return 0;
}


/*
 *  Description: Send AT command which will reply by the value  with a prefix "+CMD: " line, such as AT+CSQ:
 *  Reply:   \r\n+CSQ: 26,99\r\nOK\r\n
 *
 * Return Value: 0: OK     -X: Failure
 */
int send_atcmd_check_request(char *atcmd, unsigned int timeout,char *outbuf, int size_outbuf)
{
    int                     i = 0;
    int                     rv;
    char                    buf[ATCMD_REPLY_LEN];
    char                   *ptr_start, *ptr_end;

    if( NULL == atcmd || NULL == outbuf || size_outbuf<=0 )
    {
    	at_printf("%s--->Invalid input arguments\r\n",__FUNCTION__);
        return -1;
    }

    /*send AT command */
    rv = send_atcmd(atcmd, NULL, timeout, buf, sizeof(buf));
    if( rv < 0 )
    {
    	at_printf("send_atcmd failure, rv=%d\r\n", rv);
        return -2;
    }

    /*Find start position */
#if 0
    ptr_start=strchr(buf, '+');  /* found '+' before the value */
    if( !ptr_start )
    {
        return -3;
    }
    ptr_start++;   /* skip '+'  */
#endif

    ptr_start=strchr(buf, ':');  /* found ':' before the value */
    if( !ptr_start )
    {
        return -4;
    }
    ptr_start++;   /* skip ':'  */

    /*Find end position */
    ptr_end=strstr(buf, "\r\nOK\r\n");
    if( !ptr_end )
    {
        return -5;
    }

    if( *(ptr_end-1) == '\n' )
    {
    	ptr_end -= 2; /* remove previous \r\n */
    }

    /*copy reply out*/
    memset(outbuf, 0, size_outbuf);
    while(ptr_start<ptr_end && i<size_outbuf)
    {
    	outbuf[i++] = *ptr_start;
        ptr_start ++;
    }

    return 0;
}

/*
 * Send the "AT" command to the module to confirm whether the module responds normally
 *
 */
int send_atcmd_check_module(void)
{
	int			rv = -3;

		rv = send_atcmd_check_ok("AT\r", 500);
		if(-1 == rv)
		{
			at_printf("%s--->Invalid input arguments\r\n",__FUNCTION__);
			return -1;
		}

		if( !rv )
		{
			at_printf("INFO: Send 'AT' to BC28 NB-IoT module and got reply ok\r\n");
			return 0;
		}

		HAL_Delay(100);

	return -1;
}

